package numericalSim;

import java.util.ArrayList;

import org.omg.CORBA.portable.IndirectionException;

import simulationSupport.ParamRandom;
import simulationSupport.WaterTempSpot;
import simulationSupport.WorldModel;

public class GroupModel {
	
	private ArrayList<IndividualModel> individuals;
	private int flockSize;
	private int headingX;
	private int headingY;
	private int x;
	private int y;
	
	//Flock variables
	private int N1;
	private int N0;
	private int fishBorn;
	private int inmigrated;
	private int emigrated;
	private int casualities;
	
	private int uniqueID;
	
	//precalculated randoming
	private ParamRandom matingRand;
	
	public GroupModel()
	{
		individuals = new ArrayList<IndividualModel>();
		
		double[] prob = {0.05,0.1,0.15,0.2,0.2,0.15,0.10,0.5};
		matingRand = new ParamRandom(7.0, 1, prob);
		x = 0;
		y = 0;
		uniqueID = 0;
	}
	
	public void addIndividuals(IndividualModel fish) {
		individuals.add(fish);
		uniqueID ++;
	}
	
	public void addStartingIndividual(int mgy,char gender,double weigth,double length)
	{
		individuals.add(IndividualModel.addFish(mgy, uniqueID, gender, weigth, length));
		uniqueID ++;
	}
	
	public IndividualModel getIndividual(int id) {
		for(int i=0;i<flockSize;i++)
		{
			IndividualModel fish = individuals.get(i);
			if(id == fish.getID())
			{
				return fish;
			}
		}
		return null;
	}
	
	public void updateFlock(ArrayList<PredatorModel> preds,ArrayList<WaterTempSpot> waters)
	{
		for(IndividualModel fish : individuals)
		{
			fish.increaseAge();
		}
		int aux = N0 + fishBorn + inmigrated - emigrated - casualities;
		N0 = N1;
		N1 = aux;
		//updating x,y
		double avgSpeed = 0;
		for(IndividualModel i : individuals)
		{
			avgSpeed += i.getSpeed(); 
		}
		avgSpeed /= individuals.size();
		
		calculateMating();
		calculateEmigration();
		calculateInmigration();
		calculateCasuality(preds);
		calculateNewHeading(preds,waters);
		calculateNewCoordinates();
	
	}
	
	public void calculateMating()
	{
		//per every grown(Y>1) pair,calculate probable ( P : Curve ) 
		fishBorn = 0;
		//1: Find how many pairs
		int pairs = 0;
		for(int k=0;k<individuals.size();k++)
		{
			if(individuals.get(k).getAge() > 12)
			{
				pairs +=1;
			}
		}
		pairs /= 2;
		
		for(int i = 0;i<pairs;i++)
		{
			fishBorn += matingRand.getRandomedTarget();
		}
		
		for (int j=0;j<fishBorn;j++)
		{
			IndividualModel newFish = IndividualModel.birthFish(12, uniqueID,WorldModel.minWeigth , WorldModel.increment);
			uniqueID ++;
			individuals.add(newFish);
		}
		
	}
	public void calculateEmigration()
	{
		this.emigrated = 0;
		//1 : Just run a P = 0.05 with a fish 1.5 Y
		for(int i=0;i<individuals.size();i++)
		{
			IndividualModel sample = individuals.get(i);
			if(sample.getAge() > 1)
			{
				if(0.05 > Math.random()){
					individuals.remove(i);
					emigrated++;
				}
				else if(0.2 > Math.random() && individuals.size() > 300000)
				{
					individuals.remove(i);
					emigrated++;
				}
			}
		}
	}
	public void calculateCasuality(ArrayList<PredatorModel> preds)
	{
		this.casualities = 0;
		//1 : Run through old fish (Y>3 : P=0.05) and very young(Y<.5 , P = 0.15)
		for(int i=0;i<individuals.size();i++)
		{
			IndividualModel sample = individuals.get(i);
			double rsl  = Math.random();
			if(sample.getAge() < 6 && rsl<0.20)
			{
				individuals.remove(i);
				casualities++;
			}
			else if(sample.getAge() > sample.getMaxgrowthyears()*2 && rsl<0.05)
			{
				individuals.remove(i);
				//0.05
				casualities++;
			}
			else if(sample.getAge() > sample.getMaxgrowthyears()*3)
			{
				individuals.remove(i);//0.15
				casualities++;
			}
			else if(rsl<0.01)
			{
				individuals.remove(i);//0.005
				casualities++;
			}
		}
		for(PredatorModel p : preds)
		{
			if( Math.abs(p.getX()- this.x)<15 && Math.abs(p.getY() - this.y)<15 )
			{
				for(IndividualModel i : individuals)
				{
					if(i.getCatchability() <= p.getIndex() && (Math.random())< 0.15 )
					{
						individuals.remove(i);
						casualities++;
						System.out.println("bing");
					}
				}
			}
		}
		
		
		//2. Check predators and catchability index. If lower, P = 0.6/N1 (flock factor)
	}
	public void calculateInmigration()
	{
		if(Math.random()<0.05)
		{
			IndividualModel newFish = IndividualModel.birthFish(12, uniqueID,WorldModel.minWeigth , WorldModel.increment);
			uniqueID ++;
			individuals.add(newFish);
		}
	}
	public void calculateNewHeading(ArrayList<PredatorModel> preds,ArrayList<WaterTempSpot> waters)
	{
		//can use a more sophisticated calculation
		this.headingX = (int) (Math.random()*100);
		this.headingY = (int) (Math.random()*100);
	}
	
	public void calculateNewCoordinates()
	{
		if(Math.random()<= 0.5 || x<0 || y<0 || y<800 || x<800){
			x = x + (int)(headingX)/2;
			y = y + (int)(headingY)/2;
		}
		else
		{
			x = x - (int)(headingX)/2;
			y = y - (int)(headingY)/2;
		}
	}
	
	public int getFlockSize() {
		return individuals.size();
	}

	public int getHeadingX() {
		return headingX;
	}

	public int getHeadingY() {
		return headingY;
	}

	public int getN1() {
		return N1;
	}

	public int getN0() {
		return N0;
	}

	public int getFishBorn() {
		return fishBorn;
	}

	public int getInmigrated() {
		return inmigrated;
	}

	public int getEmigrated() {
		return emigrated;
	}

	public int getCasualities() {
		return casualities;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	
	
	
}
